<cfcomponent displayname="PageManager" output="false" hint="PageManager bean for ScriptWriter system.">
	
	<cfproperty name="siteRoot" type="string" />
	<cfproperty name="pathToManagers" type="string" />
	<cfproperty name="classPath" type="string" />
	<cfproperty name="factory" type="any" />
	<cfproperty name="outputStore" type="struct" />
	
	
	<!--- init() --->
	<cffunction name="init" access="public" returntype="any">
		<cfargument name="siteRoot" type="string" required="yes" />
		<cfargument name="pathToManagers" type="string" required="yes" />
		<cfargument name="factory" type="any" required="yes" />
		<cfscript>
			setSiteRoot(arguments.siteRoot);
			setPathToManagers(arguments.pathToManagers);
			setFactory(arguments.factory);
			setOutputStore(StructNew());
			buildClassPath();
			return this;
		</cfscript>
	</cffunction>
	
	
	<!--- run() --->
	<cffunction name="run" access="public" returntype="void">
		<cfargument name="request" type="string" required="yes" />
		<cfargument name="action" type="string" required="yes" />
		<cfargument name="args" type="struct" required="no" default="#StructNew()#" />
		<cfscript>
			var local = {};

			// Translate the action argument to a component name and method
			local.component = ListGetAt(arguments.action,1,".");
			local.method = ListGetAt(arguments.action,2,".");
			
			// Inject the action value into the arguments so we can easily pass
			// it to the next cfc by invoke
			StructInsert(arguments.args, "action", arguments.action);
			
			// Use the translated component name and method to use cfinvoke,
			// firing that component.method() and passing in any arguments
			cfinvoke(
				component = "#getClassPath()#.#local.component#",
				method = local.method,
				args = arguments.args
			);
		</cfscript>
	</cffunction>
	
	
	<!--- autoGenerate() --->
	<cffunction name="autoGenerate" access="public" returntype="any">
		<cfargument name="request" type="string" required="no" default="#CreateUUID()#" />
		<cfscript>
			var local = {};
			
			// Get a list of the CFCs in the manager directory
			local.managerFileList = DirectoryList(getPathToManagers());
			
			// Loop over these CFCs
			for (local.i = 1; local.i LTE ArrayLen(local.managerFileList); local.i++) {
				
				local.componentName = ListFirst(ListLast(local.managerFileList[local.i],"\"),".");
				local.componentClassPath = getClassPath() & "." & local.componentName;
				local.managerFunctions = GetComponentMetaData(local.componentClassPath).functions;

				// Loop over the functions in the CFC
				for (local.x = 1; local.x LTE ArrayLen(local.managerFunctions); local.x++) {
					
					// only process public functions
					if (local.managerFunctions[local.x].access EQ "public") {
						StructInsert(arguments, "action", "#local.componentName#.#local.managerFunctions[local.x].name#");
						cfinvoke(
							component = local.componentClassPath,
							method = local.managerFunctions[local.x].name,
							args = arguments
						);	
					}
				}
			}
			
		</cfscript>
	</cffunction>
	
	
	<!--- cfinvoke() --->
	<cffunction name="cfinvoke" access="private" returntype="void">
		<cfargument name="component" type="string" required="yes" />
		<cfargument name="method" type="string" required="yes" />
		<cfargument name="args" type="struct" required="no" default="#StructNew()#" />
		<cfset local = {} />
		<cfset local.initArgs = StructNew() />
		<cfset local.initArgs.factory = getFactory() />
		<cfset local.initArgs.pageManager = this />
		<cfinvoke component="#arguments.component#" method="init" returnvariable="local.initReturn" argumentcollection="#local.initArgs#" />
		<cfinvoke component="#local.initReturn#" method="#arguments.method#" returnvariable="local.invokeReturn" argumentcollection="#arguments.args#" />
	</cffunction>
	
	
	<!--- buildClassPath() --->
	<cffunction name="buildClassPath" access="private" returntype="void">
		<cfscript>
			var local = {};
			local.classPath = Replace(getPathToManagers(), ExpandPath(getSiteRoot()), "");
			local.classPath = Replace(local.classPath, "\", ".");
			setClassPath(local.classPath);
		</cfscript>
	</cffunction>
	
	
	<!--- actionKeyToTRGKey() --->
	<cffunction name="actionKeyToTRGKey" access="public" output="no" returntype="string">
		<cfargument name="original" type="string" required="yes" />
		<cfargument name="attributes" type="struct" required="yes" />
		<cfscript>
			var local = {};
			local.allowedKeys = "type,region,group";
			local.workingString = arguments.original;	
			for (local.key in arguments.attributes) {
				if (FindNoCase(local.key, local.allowedKeys)) {
					local.workingString &= "_#local.key#:#StructFind(arguments.attributes, local.key)#";
				}
			}
			return LCase(local.workingString);
		</cfscript>
	</cffunction>
	
	
	<!--- trgKeyToComboKey() --->
	<cffunction name="trgKeyToComboKey" access="public" output="no" returntype="string">
		<cfargument name="original" type="string" required="yes" />
		<cfscript>
			var local = {};
			local.workingString = arguments.original & "_combo";	
			return LCase(local.workingString);
		</cfscript>
	</cffunction>
	
	
	<!--- trgKeyToRequestKey() --->
	<cffunction name="trgKeyToRequestKey" access="public" output="no" returntype="string">
		<cfargument name="original" type="string" required="yes" />
		<cfargument name="requestID" type="string" required="yes" />
		<cfscript>
			var local = {};
			local.workingString = arguments.original & "_request:" & arguments.requestid;	
			return LCase(local.workingString);
		</cfscript>
	</cffunction>
	
	
	<!--- getFromCache() --->
	<cffunction name="getFromCache" access="public" output="no" returntype="any">
		<cfargument name="key" type="string" required="yes" />
		<cfscript>
			var local = {};
			local.cacheType = getFactory().getCacheType();
			if (local.cacheType EQ "struct") {
				if (StructKeyExists(getOutputStore(), arguments.key)) {
					return StructFind(getOutputStore(), arguments.key);
				}
				else {
					return JavaCast("null", 0);
				}
				
			}
			else if (local.cacheType EQ "ehcache") {
				return CacheGet(arguments.key);
			}
		</cfscript>
	</cffunction>
	
	
	<!--- saveToCache() --->
	<cffunction name="saveToCache" access="public" output="no" returntype="void">
		<cfargument name="key" type="string" required="yes" />
		<cfargument name="data" type="string" required="yes" />
		<cfscript>
			var local = {};
			local.cacheType = getFactory().getCacheType();
			
			if (local.cacheType EQ "struct") {
				if (NOT StructKeyExists(getOutputStore(), arguments.key)) {
					StructInsert(getOutputStore(), arguments.key, arguments.data);
				}
				else {
					StructUpdate(getOutputStore(), arguments.key, arguments.data);	
				}
				
			}
			else {
				CachePut(arguments.key, arguments.data, CreateTimeSpan(0,0,0,10));
			}
		</cfscript>
	</cffunction>
	
	
	<!--- generateCacheMapStructKey() --->
	<cffunction name="generateCacheMapStructKey" access="public" output="no" returntype="string">
		<cfargument name="attributes" type="struct" required="yes" />
		<cfreturn "#arguments.attributes.request#_#arguments.attributes.type#_#arguments.attributes.region#_#arguments.attributes.group#" />
	</cffunction>
	
	
	<!--- getSiteRoot() --->
	<cffunction name="getSiteRoot" access="public" output="no" returntype="string">
		<cfreturn variables.instance["siteRoot"] />
	</cffunction>
	
	
	<!--- setSiteRoot() --->
	<cffunction name="setSiteRoot" access="public" output="no" returntype="void">
		<cfargument name="path" type="string" required="yes" />
		<cfset variables.instance["siteRoot"] = arguments.path />
	</cffunction>
	
	
	<!--- getPathToManagers() --->
	<cffunction name="getPathToManagers" access="public" output="no" returntype="string">
		<cfreturn variables.instance["pathToManagers"] />
	</cffunction>
	
	
	<!--- setPathToManagers() --->
	<cffunction name="setPathToManagers" access="public" output="no" returntype="void">
		<cfargument name="path" type="string" required="yes" />
		<cfset variables.instance["pathToManagers"] = arguments.path />
	</cffunction>
	
	
	<!--- getClassPath() --->
	<cffunction name="getClassPath" access="public" output="no" returntype="string">
		<cfreturn variables.instance["classPath"] />
	</cffunction>
	
	
	<!--- setClassPath() --->
	<cffunction name="setClassPath" access="public" output="no" returntype="void">
		<cfargument name="path" type="string" required="yes" />
		<cfset variables.instance["classPath"] = arguments.path />
	</cffunction>
	
	
	<!--- getFactory() --->
	<cffunction name="getFactory" access="public" output="no" returntype="any">
		<cfreturn variables.instance["factory"] />
	</cffunction>
	
	
	<!--- setFactory() --->
	<cffunction name="setFactory" access="public" output="no" returntype="void">
		<cfargument name="factory" type="any" required="yes" />
		<cfset variables.instance["factory"] = arguments.factory />
	</cffunction>
	
	
	<!--- getOutputStore() --->
	<cffunction name="getOutputStore" access="public" output="no" returntype="struct">
		<cfreturn variables.instance["outputStore"] />
	</cffunction>
	
	
	<!--- setOutputStore() --->
	<cffunction name="setOutputStore" access="public" output="no" returntype="void">
		<cfargument name="store" type="struct" required="yes" />
		<cfset variables.instance["outputStore"] = arguments.store />
	</cffunction>
	

</cfcomponent>